/**
 * TeachizenMailLibarary
 * Pop3Client.java
 *
 * Copyright 2013 bnsworks
 * Written by htkim
 *	2013. 10. 9. first written.
 *
 * note:
 */
package com.teachizen.mail.receive.pop;

import java.util.*;

import javax.mail.*;

import lombok.extern.slf4j.*;

import com.sun.mail.pop3.*;
import com.teachizen.mail.receive.*;

/**
 * @author cloudstick
 *
 */
@Slf4j
public class Pop3Client {

	private Pop3Client() { }

	private final static String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
	private static final Pop3Client instance = new Pop3Client();

	private static Properties props;
	private static Session session;

	private Store store = null;
	private Folder folder = null;

	public static Pop3Client getInstance() {
		return instance;
	}

	public void init(final ServerInfo serverInfo) throws NoSuchProviderException {
		props = System.getProperties();
	
		/*
		if (serverInfo.secure == null || !"none".equalsIgnoreCase(serverInfo.secure)) {
			//props.setProperty("mail.pop3.socketFactory.class", SSL_FACTORY);
		    //props.setProperty("mail.pop3.socketFactory.fallback", "false");
		    props.setProperty("mail.pop3.host", serverInfo.url);
		    props.setProperty("mail.pop3.port", serverInfo.port);
		    //props.setProperty("mail.pop3.socketFactory.port", serverInfo.port);
		}
		*/
		props.setProperty("mail.pop3.socketFactory.class", SSL_FACTORY);
	    props.setProperty("mail.pop3.socketFactory.fallback", "false");
	    props.setProperty("mail.pop3.host", serverInfo.url);
	    props.setProperty("mail.pop3.port", serverInfo.port);
	    props.setProperty("mail.pop3.socketFactory.port", serverInfo.port);
	    props.setProperty("mail.smtp.starttls.enable","true");
		/*
	    URLName url = new URLName("pop3",serverInfo.url,
	    		Integer.parseInt(serverInfo.port),
	    		"",
	    		serverInfo.username,
	    		serverInfo.password);
		*/
		session = Session.getDefaultInstance(props);
		store = session.getStore("pop3");
		
		try {
			store.connect(serverInfo.username, serverInfo.password);
		} catch (MessagingException e) {
			log.error("Exception occured while connecting store.", e);
			throw new ReceiveException("Exception occured while connecting store.", e);
		}

		try {
			folder = store.getFolder("INBOX");
		} catch (MessagingException e) {
			log.error("Exception occured while getting inbox folder.", e);
			throw new ReceiveException("Exception occured while getting inbox folder.", e);
		}

		try {
			folder.open(Folder.READ_WRITE);
		} catch (MessagingException e) {
			log.error("Exception occured while openning inbox folder.", e);
			throw new ReceiveException("Exception occured while openning inbox folder.", e);
		}
	}

	public void cleanup() {
		try {
			if (folder != null) {
				if (folder.isOpen()) {
					folder.close(true);
				}
			}
			if (store != null) {
				store.close();
			}
		} catch(Exception ignore) { }
	}

	public Message getMessage(final int number) {
		try {
			Message message = (Message)folder.getMessage(number);
			return message;
		} catch (Exception e) {
			log.error("Exception occured while getting pop3 message.", e);
			throw new ReceiveException("Exception occured while getting pop3 message.", e);
		}
	}

	public List<Message> getMessages() {
		try {
			Message[] messages = (Message[])folder.getMessages();
			if (messages == null || messages.length == 0) {
				log.info("Pop3 message is empty.");
				return null;
			}
			return new ArrayList<Message>(Arrays.asList(messages));
		} catch (MessagingException e) {
			log.error("Exception occured while getting pop3 messages.", e);
			throw new ReceiveException("Exception occured while getting pop3 messages.", e);
		}
	}

	public List<Message> getMessages(final int startNumber, final int endNumber) {
		try {
			Message[] messages = (Message[])folder.getMessages(startNumber, endNumber);
			if (messages == null || messages.length == 0) {
				log.info("Pop3 message is empty.");
				return null;
			}
			return new ArrayList<Message>(Arrays.asList(messages));
		} catch (MessagingException e) {
			log.error("Exception occured while getting pop3 messages.", e);
			throw new ReceiveException("Exception occured while getting pop3 messages.", e);
		}
	}

	public List<Message> getMessages(final int[] numbers) {
		try {
			Message[] messages = (Message[])folder.getMessages(numbers);
			if (messages == null || messages.length == 0) {
				log.info("Pop3 message is empty.");
				return null;
			}
			return new ArrayList<Message>(Arrays.asList(messages));
		} catch (Exception e) {
			log.error("Exception occured while getting pop3 messages.", e);
			throw new ReceiveException("Exception occured while getting pop3 messages.", e);
		}
	}

	public int getMessageCount() throws Exception {
		try {
			return folder.getMessageCount();
		} catch (MessagingException e) {
			log.error("Exception occured while getting pop3 message count.", e);
			throw new ReceiveException("Exception occured while getting pop3 message count.", e);
		}
	}

	public List<Folder> getFolders() {
		try {
			Folder[] folders = store.getDefaultFolder().list("*");
			if (folders == null || folders.length == 0) {
				log.info("Pop3 folder list is empty.");
				return null;
			}
			return new ArrayList<Folder>(Arrays.asList(folders));
		} catch (MessagingException e) {
			log.error("Exception occured while getting pop3 folders.", e);
			throw new ReceiveException("Exception occured while getting pop3 folders.", e);
		}
	}
}
